package com.gitee.cui.server.server;


import com.gitee.cui.common.common.codec.SimpleProtobufDecoder;
import com.gitee.cui.common.common.codec.SimpleProtobufEncoder;
import com.gitee.cui.server.handler.LoginRequestHandler;
import com.gitee.cui.server.handler.ServerExceptionHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.PooledByteBufAllocator;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * 聊天服务端
 *
 * @author cuiqingqiang
 * @version 1.0
 * @date 2021-10-27 22:58
 **/
@Slf4j
@Data
@Service
public class ChatServer {

	@Autowired
	private LoginRequestHandler loginRequestHandler;

	@Autowired
	private ServerExceptionHandler serverExeptionHandler;

	@Value("${server.port}")
	private int port;

	private ServerBootstrap bootstrap = new ServerBootstrap();

	private EventLoopGroup boss;

	private EventLoopGroup worker;

	/**
	 * 启动聊天程序服务端
	 */
	public void runServer () {
		// 连接监听线程组
		boss = new NioEventLoopGroup(1);
		// 工作线程组
		worker = new NioEventLoopGroup();

		try {
			bootstrap.group(boss, worker);
			bootstrap.channel(NioServerSocketChannel.class);
			bootstrap.option(ChannelOption.ALLOCATOR, PooledByteBufAllocator.DEFAULT);
			bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
			bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
				@Override
				protected void initChannel(SocketChannel ch) throws Exception {
					ch.pipeline().addLast(new SimpleProtobufDecoder());
					ch.pipeline().addLast(new SimpleProtobufEncoder());
					// 在流水线中添加handler来处理登录请求，登录成功后删除
					ch.pipeline().addLast("login", loginRequestHandler);
					// 添加异常处理器
					ch.pipeline().addLast(serverExeptionHandler);
				}
			});
			bootstrap.localAddress(port);

			ChannelFuture future = bootstrap.bind();
			future.sync();
			Channel channel = future.channel();
			log.info("聊天服务端启动成功，端口号：" + channel.localAddress());

			channel.closeFuture().sync();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} finally {
			worker.shutdownGracefully();
			boss.shutdownGracefully();
		}
	}
}
